package concurrent

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

func TestChannel1() {
	var ch1 chan int
	var ch2 chan bool
	var ch3 chan []int

	ch1 = make(chan int)
	ch2 = make(chan bool)
	ch3 = make(chan []int)

	close(ch1)
	fmt.Println(ch1)
	fmt.Println(ch2)
	fmt.Println(ch3)

	ch4 := make(chan int, 2)
	ch4 <- 1
	ch4 <- 2
	//ch4 <- 3
}

func recv1(ch chan int) {
	for i := range ch {
		fmt.Println(i * i)
	}
}

func TestChannel2() {
	ch := make(chan int)
	go recv1(ch)

	for i := 1; i <= 10; i++ {
		ch <- i
	}
	close(ch)
	fmt.Println("success")
}

func TestChannel3() {
	ch1 := make(chan int, 10)
	ch2 := make(chan int, 10)

	go func() {
		for i := 0; i < 10; i++ {
			ch1 <- i
		}
		close(ch1)
	}()

	go func() {
		for {
			i, ok := <-ch1
			if !ok {
				break
			}

			ch2 <- i * i
		}
		close(ch2)
	}()

	for i := range ch2 {
		fmt.Println(i)
	}
}

func counter(out chan<- int) {
	for i := 0; i <= 10; i++ {
		out <- i
	}

	close(out)
}

func calc(out chan<- int, in <-chan int) {
	for i := range in {
		out <- i * i
	}
	close(out)
}

func print(in <-chan int) {
	for i := range in {
		fmt.Println(i)
	}
}

func TestChannel4() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	go counter(ch1)
	go calc(ch2, ch1)
	print(ch2)
}

func worker(id int, jobs <-chan int, results chan<- int) {
	for j := range jobs {
		//fmt.Printf("worker: %d, start job: %d\n", id, j)
		time.Sleep(time.Second)
		//fmt.Printf("worker: %d, end job: %d\n", id, j)

		results <- j * 2
	}
}

func TestWorkerPool() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)

	//开启3个goroutine的goroutine池
	for w := 1; w <= 3; w++ {
		go worker(w, jobs, results)
	}

	//插入任务，像in channel写入值
	for j := 1; j <= 5; j++ {
		jobs <- j
	}
	close(jobs)

	//从out channel读取结果
	for j := 1; j <= 5; j++ {
		fmt.Println(<-results)
	}
}

func TestSelect() {
	ch1 := make(chan int)
	ch2 := make(chan int)
	ch3 := make(chan int)
	ch4 := make(chan int)

	go func() {
		for i := 1; i <= 10; i++ {
			ch1 <- i
		}

		for i := 11; i <= 20; i++ {
			ch2 <- i
		}

		for i := 21; i <= 30; i++ {
			ch3 <- i
		}

		for i := 31; i <= 40; i++ {
			ch4 <- i
		}

		close(ch1)
		close(ch2)
		close(ch3)
		close(ch4)
	}()

	for {
		var x int
		var ok bool
		select {
		case x, ok = <-ch1:
			fmt.Println(x)
		case x, ok = <-ch2:
			fmt.Println(x)
		case x, ok = <-ch3:
			fmt.Println(x)
		case x, ok = <-ch4:
			fmt.Println(x)
		}

		if !ok {
			break
		}
	}
}

func TestChannel5() {
	jobChan := make(chan int, 100)
	resultChan := make(chan int, 24)

	go func() {
		for i := 0; i < 10; i++ {
			ran := rand.Intn(100)
			jobChan <- ran
		}
		close(jobChan)
		fmt.Println("a end")
	}()

	go func() {
		for value := range jobChan {
			s := strconv.Itoa(value)
			sum := 0
			for _, ch := range s {
				c := int(ch - '0')
				sum += c
			}

			resultChan <- sum
		}

		close(resultChan)
		fmt.Println("b end")
	}()

	for result := range resultChan {
		fmt.Println(result)
	}
	fmt.Println("main end")
}
